---
id: testing
title: Testing
---

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
import FbIosTesting from '../fb/_ios-plugin-development-testing-ios-plugins-0.mdx';
import FbAndroidTesting from '../fb/_android-plugin-development-testing-android-plugins-0.mdx';

Developer tools are only used if they work. Testing is important as it discovers defects/bugs and improves the quality, reliability and functionality of software.
This page details the Flipper APIs that can be used to effectively test plugins.

## Writing tests

This section covers [desktop plugins](#desktop-plugins) and [client plugins](#client-plugins).

### Desktop plugins

Flipper uses [Jest](https://jestjs.io/) as a unit testing framework.

Writing unit tests for Flipper Desktop plugins is covered in detail in the [Building a Desktop Plugin](../../docs/tutorial/js-custom.mdx#testing-plugin-logic) tutorial.

The `flipper-plugin` package provide several [test utilities](../../docs/extending/flipper-plugin.mdx#testutils) to make testing more convenient.

## Client plugins

<Tabs defaultValue="android" values={[{label: 'Android', value: 'android'}, { label: 'iOS', value: 'ios'}]}>
<TabItem value="android">

<OssOnly>

Start by creating your first test file in this directory `MyFlipperPluginTest.java`. In the test method body, is the plugin to be tested as well as a `FlipperConnectionMock`.

The following example asserts that the plugin's connected status is what is expected:

```java
@RunWith(RobolectricTestRunner.class)
public class MyFlipperPluginTest {

  @Test
  public void myTest() {
    final MyFlipperPlugin plugin = new MyFlipperPlugin();
    final FlipperConnectionMock connection = new FlipperConnectionMock();

    plugin.onConnect(connection);
    assertThat(plugin.connected(), equalTo(true));
  }
}
```

There are two mock classes that are used to construct tests: `FlipperConnectionMock` and `FlipperResponderMock`. Together these can be used to write very powerful tests to verify the end-to-end functionality of your plugin.

For example, you can test if, for a given incoming message, your plugin responds as expected:

```java
@Test
public void myTest() {
  final MyFlipperPlugin plugin = new MyFlipperPlugin();
  final FlipperConnectionMock connection = new FlipperConnectionMock();
  final FlipperResponderMock responder = new FlipperResponderMock();

  plugin.onConnect(connection);

  final FlipperObject params = new FlipperObject.Builder()
      .put("phrase", "flipper")
      .build();
  connection.receivers.get("myMethod").onReceive(params, responder);

  assertThat(responder.successes, hasItem(
      new FlipperObject.Builder()
          .put("phrase", "ranos")
          .build()));
}
```

</OssOnly>

<FbAndroidTesting />

</TabItem>
<TabItem value="ios">

<OssOnly>

Start by creating your first test file `MyFlipperPluginTests.cpp` and import the testing utilities from `fbsource//xplat/sonar/xplat:FlipperTestLib`. These utilities mock out core pieces of the communication channel so that you can test your plugin in isolation.

```objc
#include <MyFlipperPlugin/MyFlipperPlugin.h>
#include <FlipperTestLib/FlipperConnectionMock.h>
#include <FlipperTestLib/FlipperResponderMock.h>

#include <folly/json.h>
#include <gtest/gtest.h>

namespace facebook {
namespace flipper {
namespace test {

TEST(MyFlipperPluginTests, testDummy) {
  EXPECT_EQ(1 + 1, 2);
}

} // namespace test
} // namespace flipper
} // namespace facebook
```

Following is a simple test using these mock utilities to create a plugin, send some data, and assert that the result is as expected:

```objc
TEST(MyFlipperPluginTests, testDummy) {
  std::vector<folly::dynamic> successfulResponses;
  auto responder = std::make_unique<FlipperResponderMock>(&successfulResponses);
  auto conn = std::make_shared<FlipperConnectionMock>();

  MyFlipperPlugin plugin;
  plugin.didConnect(conn);

  folly::dynamic message = folly::dynamic::object("param1", "hello");
  folly::dynamic expectedResponse = folly::dynamic::object("response", "Hi there");

  auto receiver = conn->receivers_["someMethod"];
  receiver(message, std::move(responder));

  EXPECT_EQ(successfulResponses.size(), 1);
  EXPECT_EQ(successfulResponses.back(), expectedResponse);
}
```

</OssOnly>

<FbIosTesting />

</TabItem>
</Tabs>

## Running (Flipper) tests

This section covers running tests on the [Flipper Desktop](#flipper-desktop) and with the [Flipper SDK](#flipper-sdk).

### Flipper Desktop

<OssOnly>

Run `yarn jest` or `yarn jest --watch` in the `desktop` directory of your Flipper checkout.

</OssOnly>

<FbInternalOnly>

Run `yarn jest` or `yarn jest --watch` in `~/fbsource/xplat/sonar/desktop`

</FbInternalOnly>

### Flipper SDK

#### Android (Java)

<OssOnly>

##### Gradle

In the root directory of the checkout:

```sh
./gradlew android:test
```

</OssOnly>

<FbInternalOnly>

##### Gradle

```sh
cd fbsource/xplat/sonar
./gradlew android:test
```

##### Buck

Make the required changes then submit a diff. With regarding to testing, `buck test ...` should work, but doesn't seem to function when run in xplat on a Mac; it does function  on Mobile On Demand if you use @mode/server.

:::note Debugging note
Things do functtion if you copy the files and BUCK file to `fbandroid/javatests` and change the rule from `sonar_android_test` to `robolectric3_test`.
:::

</FbInternalOnly>

<FbInternalOnly>

### iOS

Focus on the plugins, or Flipper code you want but with the `--with-tests` param:

```sh
arc focus ... --with-tests`
```

Then, click the '<->' icon in xcode and you run from there.

</FbInternalOnly>

### React Native

For details, see the [Testing React Native Changes](testing-rn.mdx) page.
